package com.note.gateway.interceptor;

import cn.hutool.json.JSONUtil;
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.InvalidClaimException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.note.config.constants.vo.ResponseVo;
import com.note.gateway.constants.ResponseCodeConstants;
import com.note.gateway.util.JwtUtil;
import com.note.gateway.util.RedisUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;

import java.io.IOException;
import java.io.PrintWriter;

/**
 * @Package：com.note.user.interceptor
 * @Name：JWTInterceptor
 * @Author：热伊木
 * @Email：uyevan@163.com
 * @Date：2023-12-12-16:33
 * @Description：JWT拦截器 --- 已经在GateWay网关中心实现 ---> 以下方式比较适合单体
 */

@Slf4j
/*@Component*/
public class JWTInterceptor implements HandlerInterceptor {
    private static final String ERROR_TOKEN_EMPTY = "令牌不能为空";
    private static final String ERROR_SIGNATURE_MISMATCH = "签名不匹配";
    private static final String ERROR_TOKEN_EXPIRED = "令牌已过期";
    private static final String ERROR_ALGORITHM_MISMATCH = "算法不匹配";
    private static final String ERROR_PAYLOAD_INVALID = "参数已失效";
    private static final String ERROR_INVALID_TOKEN = "无效令牌";
    private static final String ERROR_DONT_EXITS_TOKEN = "令牌已更新或不存在";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        response.setContentType("application/json;charset=UTF-8");
        //获取token
        String token = request.getHeader(JwtUtil.AUTHORIZATION);
        ResponseVo responseVo = new ResponseVo(ResponseCodeConstants.ERROR, false, "", null);
        if (null == token) {
            responseVo.setMessage(ERROR_TOKEN_EMPTY);
            writerPrintln(responseVo, response);
            return false;
        }
        /*获取账号和密码*/
        String userName = JwtUtil.getPayloadFromToken(token, "username");
        String passWord = JwtUtil.getPayloadFromToken(token, "password");
        /*如果没有问题则判断Redis中的状态*/
        if (!RedisUtils.exists(userName) || !RedisUtils.getValue(userName).equals(token)) {
            responseVo.setMessage(ERROR_DONT_EXITS_TOKEN);
            writerPrintln(responseVo, response);
            return false;
        }
        try {
            // 验证令牌（截取前缀）
            String replace = token.replace(JwtUtil.TOKEN_PREFIX, "");
            /*如果存在任何问题就抛出异常拦截请求*/
            JwtUtil.verify(replace);
            /*用户数据验证（是否存在 | 密码状态）都无需验证 ，相应的业务都会更新令牌*/
            return true;
        } catch (SignatureVerificationException e) {
            e.printStackTrace();
            responseVo.setMessage(ERROR_SIGNATURE_MISMATCH);
        } catch (TokenExpiredException e) {
            e.printStackTrace();
            responseVo.setMessage(ERROR_TOKEN_EXPIRED);
        } catch (AlgorithmMismatchException e) {
            e.printStackTrace();
            responseVo.setMessage(ERROR_ALGORITHM_MISMATCH);
        } catch (InvalidClaimException e) {
            e.printStackTrace();
            responseVo.setMessage(ERROR_PAYLOAD_INVALID);
        } catch (Exception e) {
            e.printStackTrace();
            responseVo.setMessage(ERROR_INVALID_TOKEN);
        }
        writerPrintln(responseVo, response);
        return false;
    }

    /*结果输出*/
    private void writerPrintln(ResponseVo responseVo, HttpServletResponse response) throws IOException {
        String json = JSONUtil.toJsonStr(responseVo);
        PrintWriter writer = response.getWriter();
        writer.println(json);
    }
}
